package cn.getech.data.development.controller.api;

import cn.getech.data.development.api.DataBaseAndTablesInfoApi;
import cn.getech.data.development.api.TableInfoApi;
import cn.getech.data.development.config.properties.BdpJobConfig;
import cn.getech.data.development.config.properties.DataDevelopmentConfig;
import cn.getech.data.development.constant.*;
import cn.getech.data.development.controller.offline.HiveTableDdl;
import cn.getech.data.development.dto.CodeTableInfoDto;
import cn.getech.data.development.entity.*;
import cn.getech.data.development.service.*;
import cn.getech.data.development.utils.HdfsUtil;
import cn.getech.data.development.utils.HiveTableUtil;
import cn.getech.data.intelligence.common.exception.RRException;
import cn.getech.data.intelligence.common.utils.R;
import cn.getech.data.intelligence.common.validator.ValidatorUtils;
import cn.getech.system.center.entity.SysSecurityDataLevelEntity;
import cn.getech.system.center.service.SysSecurityDataLevelService;
import cn.getech.system.center.utils.ShiroUtils;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName TableInfoApiController
 * @Description TODO
 * @Author Getech
 * @Date 2020/12/24 11:46
 */
@Slf4j
@RestController
public class TableInfoApiController implements TableInfoApi, DataBaseAndTablesInfoApi {

    @Autowired
    private TableInfoService tableInfoService;

    @Autowired
    private TableFieldInfoService tableFieldInfoService;

    @Autowired
    private DataDevelopmentConfig hiveConfig;

    @Autowired
    private BdpJobConfig bdpJobConfig;

    @Autowired
    private IAllPermissionConfigService iAllPermissionConfigService;


    @Autowired
    private SysSecurityDataLevelService sysSecurityDataLevelService;

    @Autowired
    private TableRelationshipService tableRelationshipService;

    @Autowired
    private TableRegisterService tableRegisterService;

    private static Map<String, Integer> uniqueMap = Maps.newHashMap();//防止添加表重复点击

    @Override
    public void dropTables(String tableIds) {
        tableInfoService.dropTables(tableIds);
    }

    @Override
    public R deleteHiveTable(String tableName) {
        //删除数据
        HdfsUtil hdfsUtil = null;
        HiveTableUtil hiveTableUtil= new HiveTableUtil(hiveConfig.getHiveserverurl(), "dim", "hdfs", "hdfs");
        try {
            hdfsUtil = new HdfsUtil(bdpJobConfig);
            hiveTableUtil.dropTable(tableName);
            hdfsUtil.delete(HiveTableUtil.genTableLocation("dim",tableName));
            return R.ok();
        } catch (Exception e) {
            return R.error(e.getMessage());
        }finally {
            if(null != hdfsUtil){
                hdfsUtil.close();
            }
            if(null != hiveTableUtil){
                hiveTableUtil.close();
            }
        }
    }

    public R save(TableInfo tableInfo) {
        long startTime = new Date().getTime();
        ValidatorUtils.validateEntity(tableInfo);
        //表名均为小写
        tableInfo.setTableName(tableInfo.getTableName().toLowerCase());
        if (CollectionUtils.isEmpty(tableInfo.getTableFieldInfos())) {
            return R.error("表中字段不能为空！");
        }
        if (!checkTableColumn(tableInfo)) {
            return R.error("表中至少有一列字段不是分区字段且字段名不可重复");
        }
        checkTableInfo(tableInfo);
        checkFieldInfo(tableInfo.getTableFieldInfos());
        String key = tableInfo.getDbName() + tableInfo.getTableName();
        if (uniqueMap.containsKey(key)) {
            //防止重复提交
            return R.error("当前表在创建中，请稍后尝试");
        }
        uniqueMap.put(key, YesOrNoEnum.YES.getValue());
        try {
            R r = HiveTableDdl.createHiveTable(tableInfo, hiveConfig);
            if (null != r && r.get("code").equals(0)) {
                return R.ok();
            } else {//表创建失败
                return r;
            }
        } catch (Exception e) {
            log.error("创建表失败:", e);
            return R.error("hive表创建失败,详情如下"+e.getMessage());
        } finally {
            uniqueMap.remove(key);
        }
    }

    @Override
    public R insert(CodeTableInfoDto codeTableInfoDto) {
        HiveTableUtil hiveTableUtil = new HiveTableUtil(hiveConfig.getHiveserverurl(), codeTableInfoDto.getDbName(), "hdfs", "hdfs");
        HdfsUtil util = null;
        try {
            util = new HdfsUtil(bdpJobConfig);
            util.writeFile(codeTableInfoDto.getParams(), HiveTableUtil.genTableLocation(codeTableInfoDto.getDbName(), codeTableInfoDto.getTableName()), null, "uploadCode.txt", 1);
            hiveTableUtil.repairTable(codeTableInfoDto.getTableName());
            hiveTableUtil.close();
            return R.ok();
        } catch (Exception e) {
            if(null != util){
                util.close();
            }
            hiveTableUtil.close();
            return R.error(e.getMessage());
        }finally {
            if(null != util){
                util.close();
            }
        }

    }

    private void checkFieldInfo(List<TableFieldInfo> tableFieldInfos) {
        tableFieldInfos.forEach(f -> {
            if (StringUtils.isNotEmpty(f.getFieldAlias()) && f.getFieldAlias().length() > 100) {
                throw new RRException("字段描述请控制在100字以内");
            }
            if (StringUtils.isNotEmpty(f.getFieldName()) && f.getFieldName().length() > 100) {
                throw new RRException("字段名称请控制在100字以内");
            }
        });
    }

    private void checkTableInfo(TableInfo tableInfo) {
        if (null != tableInfo.getTableAlias() && tableInfo.getTableAlias().length() > 100) {
            throw new RRException("表描述请控制在100字以内");
        }
        if (null != tableInfo.getTableName() && tableInfo.getTableName().length() > 255) {
            throw new RRException("表名称请控制在255字以内");
        }
    }

    private Boolean checkTableColumn(TableInfo tableInfo) {
        int columns = 0;
        List<TableFieldInfo> listFields = tableInfo.getTableFieldInfos();
        listFields.sort(Comparator.comparingInt(TableFieldInfo::getFieldOrder));
        if (checkTableColumnIsRepeat(listFields))
            return false;
        for (TableFieldInfo fieldInfo : listFields) {
            if (YesOrNoEnum.NO.getValue().equals(fieldInfo.getIsPartition())) {
                columns++;
            }
        }
        return columns > 0;
    }

    private Boolean checkTableColumnIsRepeat(List<TableFieldInfo> listFields) {
        boolean tableColumnIsRepeat = false;
        Set<String> sets = listFields.stream().map(TableFieldInfo::getFieldName).collect(Collectors.toSet());
        if (sets.size() != listFields.size()) {
            tableColumnIsRepeat = true;
        }
        return tableColumnIsRepeat;
    }

    private Boolean createDbTable(TableInfo tableInfo, long startTime) {
        Long userId = tableInfo.getApplyUserId();
        tableInfo.setCreatePer(userId.intValue());
        tableInfo.setCreateTime(DateTime.now());
        tableInfo.setUpdateTime(DateTime.now());
        tableInfo.setUpdatePer(userId);
        List<AllPermissionConfig> allPermisssionList = iAllPermissionConfigService.list();
        Integer tableLevel = 0, culonm = 0, enType = 0;
        if (CollectionUtil.isNotEmpty(allPermisssionList)) {
            List<AllPermissionConfig> tableList = allPermisssionList.stream().filter(allPermissionConfig -> Objects.equals(PressionParamType.TABLE.getId(), allPermissionConfig.getPermissType())).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(tableList)) {
                tableLevel = tableList.get(0).getDataPermissionId();
            }
            List<AllPermissionConfig> culonmList = allPermisssionList.stream().filter(allPermissionConfig -> Objects.equals(PressionParamType.CULONM.getId(), allPermissionConfig.getPermissType())).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(tableList)) {
                culonm = culonmList.get(0).getDataPermissionId();
            }
            List<AllPermissionConfig> enStypeList = allPermisssionList.stream().filter(allPermissionConfig -> Objects.equals(PressionParamType.ENSTYPE.getId(), allPermissionConfig.getPermissType())).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(tableList)) {
                enType = enStypeList.get(0).getDataPermissionId();
            }
        }
        if (tableLevel != 0) {
            tableInfo.setTableLevelId(tableLevel);
        }

        SysSecurityDataLevelEntity defaultTableService = sysSecurityDataLevelService.getDefaultTableService();
        tableInfo.setSecurityDataLevel(defaultTableService.getName());
        Boolean re = tableInfoService.save(tableInfo);
        if (re) {
            TableInfo info = tableInfoService.getOne(new QueryWrapper<TableInfo>().eq("db_name", tableInfo.getDbName())
                    .eq("table_name", tableInfo.getTableName()));
            if (info == null) {
                return false;
            } else {
                List<TableFieldInfo> list = tableInfo.getTableFieldInfos();

                for (TableFieldInfo fieldInfo : list) {
                    if (YesOrNoEnum.YES.getValue().equals(info.getStoreEngine())) {// hive 引擎
                        fieldInfo.setPrimaryKey(YesOrNoEnum.NO.getValue());
                    }
                    fieldInfo.setCreatePer(tableInfo.getCreatePer());
                    fieldInfo.setTableId(info.getId());
                    fieldInfo.setCreateTime(DateTime.now());
                    if (0 != culonm) {
                        fieldInfo.setColcumLevelId(culonm);
                    }
                    if (0 != enType) {
                        fieldInfo.setEncyStyleId(enType);
                    }
                    fieldInfo.setSecurityDataLevel(defaultTableService.getName());
                    if (CollectionUtil.isEmpty(fieldInfo.getRelationshipes()))
                        continue;
                    for (TableRelationshipEntity shipEntity : fieldInfo.getRelationshipes()) {
                        shipEntity.setSourceTableId(info.getId());
                        shipEntity.setSourceTableName(info.getTableName());
                        shipEntity.setSourceFieldName(fieldInfo.getFieldName());
                    }
                    tableRelationshipService.saveBatch(fieldInfo.getRelationshipes());
                }
                tableFieldInfoService.saveBatch(list);
                Date curr = new Date();
                TableRegisterEntity registerEntity = new TableRegisterEntity();
                registerEntity.setTableInfoId(info.getId());
                registerEntity.setBatchNum(curr.getTime());
                registerEntity.setRegisterType(TableRegisterTypeEnum.OFFLINE_ADD.getCode());
                long cost = curr.getTime() - startTime;
                registerEntity.setCost(cost);
                registerEntity.setRunTime(curr);
                registerEntity.setRunUser(info.getCreatePer().longValue());
                tableRegisterService.save(registerEntity);
                // 保存物理模型  主题和类目关系
                tableInfoService.saveModelRelation(tableInfo);
                return true;
            }
        } else {
            return false;
        }
    }

    @Override
    public R listDbs() {
        return R.okWithData(DBTypeEnum.values());
    }
}
